package com.qnvip.sbd.util;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class BeanUtil {

	/**
	 * bean to map
	 * @param obj
	 * @return
	 */
	public static Map<String, Object> bean2Map(Object obj) {
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			Method[] methods = obj.getClass().getDeclaredMethods();
			for (Method method : methods) {
				if (method.getName().startsWith("get")) {
					String field = method.getName();
					field = field.substring(field.indexOf("get") + 3);
					field = field.toLowerCase().charAt(0) + field.substring(1);
					Object value = method.invoke(obj, (Object[]) null);
					map.put((String) field, (Object) (null == value ? "" : value));
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return map;
	}
	
	public static Map<String, Object> convertBean(Object bean)
			throws IntrospectionException, IllegalAccessException, InvocationTargetException {
		Class<? extends Object> type = bean.getClass();
		Map<String, Object> returnMap = new HashMap<String, Object>();
		BeanInfo beanInfo = Introspector.getBeanInfo(type);
		PropertyDescriptor[] propertyDescriptors = beanInfo .getPropertyDescriptors();
		for (int i = 0; i < propertyDescriptors.length; i++) {
			PropertyDescriptor descriptor = propertyDescriptors[i];
			String propertyName = descriptor.getName();
			if (!propertyName.equals("class")) {
				Method readMethod = descriptor.getReadMethod();
				Object result = readMethod.invoke(bean, new Object[0]);
				if (result != null) {
					returnMap.put(propertyName, result);
				} else {
					returnMap.put(propertyName, StringUtils.EMPTY);
				}
			}
		}
		return returnMap;
	}
	
	/**
	 * 
	 * @param obj
	 * @return
	 */
	public static Map<String, Object> bean2Map(Object obj, String fields) {
		Map<String, Object> map = new HashMap<String, Object>();
		fields = "," + fields + ",";
		try {
			Method[] methods = obj.getClass().getMethods();
			for (Method method : methods) {
				if (method.getName().startsWith("get")) {
					String getMethodName = method.getName();
					getMethodName = getMethodName.substring(getMethodName.indexOf("get") + 3);
					getMethodName = getMethodName.toLowerCase().charAt(0) + getMethodName.substring(1);
					if (fields.indexOf("," + getMethodName + ",") >=0 ) {
						Object value = method.invoke(obj, (Object[]) null);
						map.put((String) getMethodName, (Object) (null == value ? "" : value));
					}
				}
				
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return map;
	}
	
	
	public static Object map2Bean(Map<String, Object> map, Object obj) throws IllegalAccessException, InvocationTargetException {
		if (map == null || obj == null) {
			return null;
		}
		BeanUtils.populate(obj, map);
		return obj;
	}
	
	@SuppressWarnings("unchecked")
	public static <E> List<E> map2Bean(List<Map<String, Object>> list, Class<E> clazz) throws IllegalAccessException, InvocationTargetException, InstantiationException {
		List<E> result = new ArrayList<>();
		for (Map<String, Object> map : list) {
			Object obj = clazz.newInstance();
			obj = map2Bean(map, obj);
			result.add((E) obj);
		}
		return result;
	}
	
	/**
	 * 
	 * @param clazz
	 * @param list
	 * @param fields 指定字段
	 * @return
	 */
	public static <T> List<Map<String, Object>> bean2Map(Class<T> clazz, List<T> list, String...fields) {
		int fieldsCount = fields.length, listCount = list.size();
		if (list == null || listCount == 0 || fields == null || fieldsCount == 0)
			return new ArrayList<Map<String, Object>>();
		
		List<Map<String, Object>> result = new ArrayList<>(listCount);
		for (T t : list) {
			result.add(bean2Map(clazz, t, fields));
		}
		return result;
	}

	public static <T> Map<String, Object> bean2Map(Class<T> clazz, T t, String...fields) {
		int fieldsCount = fields.length;
		if (t == null || fieldsCount == 0) return null;
		
		Map<String, Object> result = new HashMap<>(fieldsCount);
		Method m = null;
		String[] fieldNames;
		for (String field : fields) {
			fieldNames = fieldSplit(field);
			try {
				m = clazz.getMethod("get" + StringUtil.upperFirst(fieldNames[0]));
				result.put(fieldNames[1], m.invoke(t));
			} catch (NoSuchMethodException e) {
				try {
					m = clazz.getMethod("is" + StringUtil.upperFirst(fieldNames[0]));
					result.put(fieldNames[1], m.invoke(t));
				} catch (Exception e1) {
					e1.printStackTrace();
					result.put(fieldNames[0], "");
				}
			} catch (IllegalAccessException | InvocationTargetException e) {
				result.put(fieldNames[0], "");
			}
		}
		return result;
	}
	
	private static String[] fieldSplit(String fieldName) {
		String[] result = new String[2];
		String[] fields = StringUtils.split(fieldName, ":");
		switch (fields.length) {
		case 0:
			result[0] = StringUtils.EMPTY;
			result[1] = StringUtils.EMPTY;
			break;
		case 1:
			result[0] = fields[0];
			result[1] = fields[0];
			break;
		default:
			result[0] = fields[0];
			result[1] = fields[1];
			break;
		}
		return result;
	}
	
	/**
	 * 将list中对象的指定字段取出用分隔符连接组成字符串
	 * @param list
	 * @param column  指定字段
	 * @param separator 分隔符
	 * @return
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 */
	public static <T> String getColumnValue(List<T> list, String column, String separator) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		if (list == null || list.size() == 0)
			return null;
		StringBuilder sb = new StringBuilder();
		Method m = null;
		for (T t : list) {
			m = t.getClass().getMethod("get" + StringUtil.upperFirst(column));
			sb.append(separator).append(m.invoke(t));
		}
		return sb.substring(1);
	}
	
	/**
	 * 将list中对象的指定字段取出用<b>逗号</b>连接组成字符串
	 * @param list
	 * @param column  指定字段
	 * @return
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 */
	public static <T> String getColumnValue(List<T> list, String column) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		return getColumnValue(list, column, ",");
	}
	
	/**
	 * 将对象中的字符串属性值去掉左右空格，null 的转为 ""
	 * @param t
	 * @param fields 字段数组
	 */
	public static <T> void trimToEmpty(T t, String... fields) {
		for (String field : fields) {
			try {
				String value = BeanUtils.getProperty(t, field);
				BeanUtils.setProperty(t, field, value == null ? StringUtils.EMPTY : value.trim());
			} catch (IllegalAccessException | InvocationTargetException
					| NoSuchMethodException e) {
				e.printStackTrace();
			}
		}
	}
}
